#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;
use Socket;
use File::Copy;

# command line options:

my $verbose;
my $postgresonly;
my $hostname;
my $gfuser;
my $gfdir;
my $mailserver;
my $noninteractive;
my $skipdatabasesetup;
my $force;
my $nogfpasswd;
my $admin_email;

my ($rez) = GetOptions(
    #"length=i" => \$length,    # numeric
    #"file=s"   => \$data,      # string
    "verbose"      => \$verbose,
    "pg_only"      => \$postgresonly,
    "skip_db_setup" => \$skipdatabasesetup,
    "hostname=s"   => \$hostname,
    "gfuser=s"     => \$gfuser,
    "gfdir=s"      => \$gfdir,
    "mailserver=s" => \$mailserver,
    "y|yes"        => \$noninteractive,
    "f|force"      => \$force,
    "nogfpasswd"   => \$nogfpasswd,
    "admin_email=s" => \$admin_email,
);

# openshift/docker-specific - name of the "pod" executing the installer:
my $pod_name = "";
if (exists($ENV{'MY_POD_NAME'}))
{
    $pod_name = $ENV{'MY_POD_NAME'};
}

my $jq_exec_path = "";
my $psql_exec_path = "";
my $cwd;
my $WARFILE_LOCATION = "dataverse.war"; 
my $REFERENCE_DATA_SQL = "../database/reference_data.sql";


my @CONFIG_VARIABLES;

if ($postgresonly) 
{
    @CONFIG_VARIABLES =
      ( 'POSTGRES_SERVER', 'POSTGRES_PORT', 'POSTGRES_DATABASE', 'POSTGRES_USER', 'POSTGRES_PASSWORD', 'POSTGRES_ADMIN_PASSWORD' );

} 
else 
{

    @CONFIG_VARIABLES = (
	'HOST_DNS_ADDRESS',
	'GLASSFISH_USER',
	'GLASSFISH_DIRECTORY',
	'ADMIN_EMAIL',
	'MAIL_SERVER',

	'POSTGRES_SERVER',
	'POSTGRES_PORT',
	'POSTGRES_ADMIN_PASSWORD',
	'POSTGRES_DATABASE',
	'POSTGRES_USER',
	'POSTGRES_PASSWORD',

	'SOLR_LOCATION', 
	
	'RSERVE_HOST',
	'RSERVE_PORT',
	'RSERVE_USER',
	'RSERVE_PASSWORD',

	'DOI_USERNAME',
	'DOI_PASSWORD',
	'DOI_BASEURL'

	);
}

my %CONFIG_DEFAULTS = (
    'HOST_DNS_ADDRESS',    'localhost',
    'GLASSFISH_USER',	   '',
    'GLASSFISH_DIRECTORY', '/usr/local/glassfish4',
    'GLASSFISH_USER',	   '',
    'ADMIN_EMAIL',         '',
    'MAIL_SERVER',         'mail.hmdc.harvard.edu:25',

    'POSTGRES_ADMIN_PASSWORD', 'secret',
    'POSTGRES_SERVER',   '127.0.0.1',
    'POSTGRES_PORT',     5432,
    'POSTGRES_DATABASE', 'dvndb',
    'POSTGRES_USER',     'dvnapp',
    'POSTGRES_PASSWORD', 'secret',

    'SOLR_LOCATION',     'LOCAL',

    'RSERVE_HOST',     'localhost',
    'RSERVE_PORT',     6311,
    'RSERVE_USER',     'rserve',
    'RSERVE_PASSWORD', 'rserve',

    'DOI_USERNAME',    'dataciteuser',
    'DOI_PASSWORD',    'datacitepassword',
    'DOI_BASEURL',     'https://mds.test.datacite.org',

);

my %CONFIG_PROMPTS = (
    'HOST_DNS_ADDRESS',    'Fully Qualified Domain Name of your host',
    'GLASSFISH_USER',	   'Glassfish service account username',
    'GLASSFISH_DIRECTORY', 'Glassfish Directory',
    'ADMIN_EMAIL',         'Administrator email address for this Dataverse',
    'MAIL_SERVER',         'SMTP (mail) server (and port) to relay notification messages',

    'POSTGRES_SERVER',   'Postgres Server Address',
    'POSTGRES_PORT',     'Postgres Server Port',
    'POSTGRES_ADMIN_PASSWORD', 'Postgres ADMIN password',
    'POSTGRES_DATABASE', 'Name of the Postgres Database',
    'POSTGRES_USER',     'Name of the Postgres User',
    'POSTGRES_PASSWORD', 'Postgres user password',

    'SOLR_LOCATION',     'Remote SOLR indexing service',

    'RSERVE_HOST',     'Rserve Server',
    'RSERVE_PORT',     'Rserve Server Port',
    'RSERVE_USER',     'Rserve User Name',
    'RSERVE_PASSWORD', 'Rserve User Password',

    'DOI_USERNAME',    'Datacite username',
    'DOI_PASSWORD',    'Datacite password',
    'DOI_BASEURL',    'Datacite URL'

);


my %CONFIG_COMMENTS = (
    'HOST_DNS_ADDRESS',    ":\n(enter numeric IP address, if FQDN is unavailable) ",
    'GLASSFISH_USER',      ":\nThis user will be running Glassfish service on your system.\n - If this is a dev. environment, this should be your own username; \n - In production, we suggest \"glassfish\" or another unprivileged user\n: ",
    'GLASSFISH_DIRECTORY', '',
    'ADMIN_EMAIL',         ":\n(please enter a valid email address!) ",
    'MAIL_SERVER',         '',

    'POSTGRES_SERVER',   '',
    'POSTGRES_PORT',     '',
    'POSTGRES_ADMIN_PASSWORD', ":\n - We will need this to create the user and database that the Dataverse application will be using.\n (Hit RETURN if access control is set to \"trust\" for this connection in pg_hba.conf)\n: ",
    'POSTGRES_USER',     ":\n - This is the Postgres user that the Dataverse app will be using to talk to the database\n: ",
    'POSTGRES_DATABASE', '',
    'POSTGRES_PASSWORD', '',

    'SOLR_LOCATION',     "? \n - Leave this set to \"LOCAL\" if the SOLR will be running on the same (this) server.\n Otherwise, please enter the host AND THE PORT NUMBER of the remote SOLR service, colon-separated\n (for example: foo.edu:8983)\n: ",

    'RSERVE_HOST',     '',
    'RSERVE_PORT',     '',
    'RSERVE_USER',     '',
    'RSERVE_PASSWORD', '',

    'DOI_USERNAME',    'DataCite or EZID username. Only necessary for publishing / minting DOIs.',
    'DOI_PASSWORD',    'DataCite or EZID account password.',
    'DOI_BASEURL',    'DataCite or EZID URL. Probably https://mds.datacite.org'

);


my $API_URL = "http://localhost:8080/api";

# jodbc.postgresql.org recommends 4.2 for Java 8.
# updated drivers may be obtained from
#  https://jdbc.postgresql.org/download.html
my $postgres_jdbc = "postgresql-42.2.2.jar";

# 0. A few preliminary checks:

# 0a. OS:

my $uname_out = `uname -a`;

my @uname_tokens = split( " ", $uname_out );

my $WORKING_OS;
if ( $uname_tokens[0] eq "Darwin" ) {
    print "\nThis appears to be a MacOS X system; good.\n";
    # TODO: check the OS version

    $WORKING_OS = "MacOSX";
}
elsif ( $uname_tokens[0] eq "Linux" ) {
    if ( -f "/etc/redhat-release" ) {
        print "\nThis appears to be a RedHat system; good.\n";
        $WORKING_OS = "RedHat";
        # TODO: check the distro version
    }
    else {
        print "\nThis appears to be a non-RedHat Linux system;\n";
        print "this installation *may* succeed; but we're not making any promises!\n";
        $WORKING_OS = "Linux";
    }
} else {
    print "\nWARNING: This appears to be neither a Linux or MacOS X system!\n";
    print "This installer script will most likely fail. Please refer to the\n";
    print "DVN Installers Guide for more information.\n\n";

    $WORKING_OS = "Unknown";

    my $yesnocont;

    unless ($noninteractive) {
        exit 0;
    }

    print "(Normally we would stop right there; but since the \"--yes\" option was specified, we'll attempt to continue)\n\n";

}


# 0b. host name:

if ($hostname) {
    $CONFIG_DEFAULTS{'HOST_DNS_ADDRESS'} = $hostname;
} else {
    my $hostname_from_cmdline = `hostname`;
    chop $hostname_from_cmdline;

    $CONFIG_DEFAULTS{'HOST_DNS_ADDRESS'} = $hostname_from_cmdline;
}

# 0c. check if there is the default.config file with the pre-set configuration values: 

#  read default configuration values from tab separated file "default.config" if it exists
#  moved after the $hostname_from_cmdline section to avoid excessively complicating the logic
#  of command line argument, automatic selection, or config file.
#
#  NOTE: if the file contain any Postgres configuration (for example: "POSTGRES_USER   dvnApp")
#  but an environmental variable with the same name exists - THE ENV. VAR WILL WIN! (don't ask)
#  (actually this is to accommodate the openshift docker deployment scenario)

sub trim { my $s = shift; $s =~ s/^\s+|\s+$//g; return $s };

my $config_default_file = "default.config";

if ( -e $config_default_file )
{
	print("loading default configuration values from $config_default_file\n");
	open( my $inp_cfg, $config_default_file );
	while( my $ln = <$inp_cfg> )
	{
		my @xs = split('\t', $ln );
		if ( 2 == @xs )
		{
			my $k = $xs[0];
                        my $v = trim($xs[1]);
#                        if (defined $ENV{$k} && ($k eq "POSTGRES_USER" || $k eq "POSTGRES_PASSWORD")) {
#                            $v = $ENV{$k};
#                        }
#                        if (defined $ENV{'POSTGRESQL_ADMIN_PASSWORD'} && $k eq "POSTGRES_ADMIN_PASSWORD")   {
#                            $v = $ENV{'POSTGRESQL_ADMIN_PASSWORD'};
#                        }
                        $CONFIG_DEFAULTS{$k}=$v;
		}
	}
}
else
{
	print("using hard-coded default configuration values (no $config_default_file available)\n");
}

# 0d. current OS user. (the first one we find wins)

my $current_user = $ENV{LOGNAME} || $ENV{USER} || getpwuid($<);

# if the username was specified on the command-line, it takes precendence:
if ($gfuser) {
    print "Using CLI-specified user $gfuser.\n";
    $CONFIG_DEFAULTS{'GLASSFISH_USER'} = $gfuser;
}


if (!$CONFIG_DEFAULTS{'GLASSFISH_USER'}) {
   $CONFIG_DEFAULTS{'GLASSFISH_USER'} = $current_user;
   print "No pre-configured user found; using $current_user.\n";
}


# prefer that we not install as root.
unless ( $< != 0 ) {
print "####################################################################\n";
print "     It is recommended that this script not be run as root.\n";
print " Consider creating a glassfish service account, giving it ownership\n";
print "  on the glassfish/domains/domain1/ and glassfish/lib/ directories,\n";
print "    along with the JVM-specified files.dir location, and running\n";
print "       this installer as the user who will launch Glassfish.\n";
print "####################################################################\n";
}

# ensure $gfuser exists or bail
my $gfidcmd="id $CONFIG_DEFAULTS{'GLASSFISH_USER'} > /dev/null";
my $gfreturncode=system($gfidcmd);
if ($gfreturncode != 0) {
   die "Couldn't find user $gfuser. Please ensure the account exists and is readable by the user running this installer.\n";
}

# 0e. the following 2 options can also be specified on the command line, and 
# also take precedence over the default values that are hard-coded and/or 
# provided in the default.config file:

if ($mailserver) {
    $CONFIG_DEFAULTS{'MAIL_SERVER'} = $mailserver;
}

if ($gfdir) {
    $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'} = $gfdir;
}

# 1. CHECK FOR SOME MANDATORY COMPONENTS (WAR FILE, ETC.)
# since we can't do anything without these things in place, better check for 
# them before we go into the interactive config mode. 
# (skip if this is a database-only setup)

unless ($postgresonly) 
{
# 1a. war file: 
    print "\nChecking if the application .war file is available... ";

# if this installer section is running out of the installer zip bundle directory,
# the war file will be sitting right here, named "dataverse.war": 

    $WARFILE_LOCATION = "dataverse.war"; 

# but if it's not here, this is probably a personal development 
# setup, so their build should be up in their source tree:

    unless ( -f $WARFILE_LOCATION ) {
	my $DATAVERSE_VERSION = "";
	my $DATAVERSE_POM_FILE = "../../pom.xml";
	if ( -f $DATAVERSE_POM_FILE ) 
	{
	    open DPF, $DATAVERSE_POM_FILE; 
	    my $pom_line;
	    while ($pom_line=<DPF>)
	    {
		chop $pom_line;
		if ($pom_line =~/^[ \t]*<version>([0-9\.]+)<\/version>/)
		{
		    $DATAVERSE_VERSION=$1;
		    last;
		}	    
	    }
	    close DPF;
	    
	    if ($DATAVERSE_VERSION ne "") {
		$WARFILE_LOCATION = "../../target/dataverse-" . $DATAVERSE_VERSION . ".war";
	    }
	}
    }

# But, if the war file cannot be found in either of the 2
# places - we'll just have to give up:

    unless ( -f $WARFILE_LOCATION ) {
	print "\nWARNING: Can't find the project .war file!\n";
	print "\tAre you running the installer in the right directory?\n";
	print "\tHave you built the war file?\n";
	print "\t(if not, build the project and run the installer again)\n";
	
	exit 0;
    }
    print " Yes, it is!\n";


# 1b. check and remember the working dir:
    chomp( $cwd = `pwd` );

# 1c. check if the reference data SQL file is there:

    $REFERENCE_DATA_SQL = "../database/reference_data.sql";

    unless ( -f $REFERENCE_DATA_SQL ) {
	# if it's not in ../database, then we're probably running out of the 
	# unzipped installer bundle, so it should be right here in the current directory:
	$REFERENCE_DATA_SQL = "reference_data.sql";
    }

    unless ( -f $REFERENCE_DATA_SQL ) {
	print "\nWARNING: Can't find .sql data template!\n";
	print "(are you running the installer in the right directory?)\n";
	
	exit 0;
    }

# 1d. jq executable: 

    my $sys_path = $ENV{'PATH'};
    my @sys_path_dirs = split( ":", $sys_path );

    if ( $pod_name ne "start-glassfish") # Why is that again? 
    {
	for my $sys_path_dir (@sys_path_dirs) {
	    if ( -x $sys_path_dir . "/jq" ) {
		$jq_exec_path = $sys_path_dir;
		last;
	    }
	}
	if ( $jq_exec_path eq "" ) {
	    print STDERR "\nERROR: I haven't been able to find the jq command in your PATH! Please install it from http://stedolan.github.io/jq/\n";
	    exit 1;

	}
    }

}


# 2. INTERACTIVE CONFIG SECTION: 

print "\nWelcome to the Dataverse installer.\n";
unless ($postgresonly) {
    print "You will be guided through the process of setting up a NEW\n";
    print "instance of the dataverse application\n";
}
else {
    print "You will be guided through the process of configuring your\n";
    print "PostgreSQL database for use by the Dataverse application.\n";
}

ENTERCONFIG:

print "\n";
print "Please enter the following configuration values:\n";
print "(hit [RETURN] to accept the default value)\n";
print "\n";

for my $ENTRY (@CONFIG_VARIABLES) 
{
    my $config_prompt = $CONFIG_PROMPTS{$ENTRY};
    my $config_comment = $CONFIG_COMMENTS{$ENTRY};

    if ( $config_comment eq '' ) 
    {
	print $config_prompt . ": ";
	print "[" . $CONFIG_DEFAULTS{$ENTRY} . "] ";
    }
    else 
    {
	print $config_prompt . $config_comment;
	print "[" . $CONFIG_DEFAULTS{$ENTRY} . "] ";
    }

    my $user_entry = "";

    # ($noninteractive means the installer is being run in the non-interactive mode; it will use 
    # the default values specified so far, without prompting the user for alternative values)\
    unless ($noninteractive) 
    {
        $user_entry = <>;
        chop $user_entry;

	if ( $user_entry ne "" ) {
	    $CONFIG_DEFAULTS{$ENTRY} = $user_entry;
	}

	# for some values, we'll try to do some validation right here, in real time:
    
	if ($ENTRY eq 'ADMIN_EMAIL') 
	{
	    $user_entry = $CONFIG_DEFAULTS{$ENTRY};
	    my $attempts = 0; 
	    while ($user_entry !~/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}/) 
	    {
		$attempts++;
		print "Please enter a valid email address: ";
		$user_entry = <>;
		chop $user_entry;
	    }

	    if ($attempts) 
	    {
		print "OK, looks legit.\n";
		$CONFIG_DEFAULTS{$ENTRY} = $user_entry;
	    }
	}
	elsif ($ENTRY eq 'GLASSFISH_DIRECTORY') 
	{
            # CHECK IF GLASSFISH DIR LOOKS OK:
	    print "\nChecking your Glassfish installation...";

	    my $g_dir = $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'};


	    unless ( -d $g_dir . "/glassfish/domains/domain1" ) 
	    {
		while ( !( -d $g_dir . "/glassfish/domains/domain1" ) ) 
		{
		    print "\nInvalid Glassfish directory " . $g_dir . "!\n";
		    print "Enter the root directory of your Glassfish installation:\n";
		    print "(Or ctrl-C to exit the installer): ";

		    $g_dir = <>;
		    chop $g_dir;
		}
	    }

	    # verify that we can write in the Glassfish directory 
	    # (now that we are no longer requiring to run the installer as root)

	    my @g_testdirs = ( "/glassfish/domains/domain1",
			       "/glassfish/domains/domain1/config",
			       "/glassfish/lib");

	    for my $test_dir (@g_testdirs)
	    {
		if (!(-w ($g_dir . $test_dir))) 
		{
		    print "\n";
		    die("ERROR: " . $g_dir . $test_dir . " not writable to the user running the installer! Check permissions on the glassfish hierarchy.\n");
		}
	    }



	    print "$g_dir looks OK!\n";
	    $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'} = $g_dir; 

	}
	elsif ($ENTRY eq 'MAIL_SERVER')
	{
	    my $smtp_server = "";
	    while (! &validate_smtp_server() )
	    {
		print "Enter a valid SMTP (mail) server:\n";
		print "(Or ctrl-C to exit the installer): ";

		$smtp_server = <>;
		chop $smtp_server;

		$CONFIG_DEFAULTS{'MAIL_SERVER'} = $smtp_server unless $smtp_server eq ''; 
	    }

	    print "\nOK, we were able to establish connection to the SMTP server you have specified.\n";
	    print "Please note that you *may* need to configure some extra settings before your \n";
	    print "Dataverse can send email. Please consult the \"Mail Host Configuration & Authentication\"\n";
	    print "section of the installation guide (http://guides.dataverse.org/en/latest/installation/installation-main.html)\n";
	    print "for more information.\n";
	}
    }

    print "\n";
}

# 2b. CONFIRM VALUES ENTERED:

print "\nOK, please confirm what you've entered:\n\n";

for my $ENTRY (@CONFIG_VARIABLES) {
    print $CONFIG_PROMPTS{$ENTRY} . ": " . $CONFIG_DEFAULTS{$ENTRY} . "\n";
}

my $yesno;
if ($noninteractive) {
    $yesno = "y";
}
else {
    print "\nIs this correct? [y/n] ";
    $yesno = <>;
    chop $yesno;
}

while ( $yesno ne "y" && $yesno ne "n" ) {
    print "Please enter 'y' or 'n'!\n";
    print "(or ctrl-C to exit the installer)\n";
    $yesno = <>;
    chop $yesno;
}

if ( $yesno eq "n" ) {
    goto ENTERCONFIG;
}

# 3. SET UP POSTGRES USER AND DATABASE

unless($pod_name eq "start-glassfish" || $pod_name eq "dataverse-glassfish-0" || $skipdatabasesetup) {
    &setup_postgres(); 
# (there's no return code - if anything goes wrong, the method will exit the script, with some diagnostic messages for the user)
    print "\nOK, done.\n";

    if ($postgresonly) 
    {
	exit 0;
    }
}

# 5. CONFIGURE GLASSFISH

my $glassfish_dir = $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'};

my $done = &setup_glassfish();

# 7. POPULATE THE DATABASE WITH REFERENCE DATA
# TODO: move this further down
# (in this step some pre-supplied content is inserted into the database that we have just created;
# it is not *necessary* for the application to run in the very basic mode; but some features - certain 
# types of metadata imports, for example - will be unavailable if it's not done. 

&import_reference_data();


# Check if the App is running: 

unless ((
     my $exit_code =
     system( $glassfish_dir . "/bin/asadmin list-applications | grep -q '^dataverse'" )
	) == 0 )
{
    # If the "asadmin list-applications" has failed, it may only mean that an earlier
    # "asadmin login" had failed, and asadmin is now failing to run without the user
    # supplying the username and password. (And the fact that we are trying to pile the  
    # output to grep prevents it from providing the prompts). 
    # So before we give up, we'll try an alternative: 

    unless ((
	my $exit_code_2 =
	system( "curl http://localhost:8080/robots.txt | grep -q '^User-agent'" )
	    ) == 0 )
    {
	print STDERR "It appears that the Dataverse application is not running...\n";
	print STDERR "Even though the \"asadmin deploy\" command had succeeded earlier.\n\n";
	print STDERR "Aborting - sorry...\n\n";

	exit 1; 
    }
}


print "\nOK, the Dataverse application appears to be running...\n\n";

# Run the additional setup scripts, that populate the metadata block field values, create users
# and dataverses, etc.

unless ( -d "data" && -f "setup-datasetfields.sh" && -f "setup-users.sh" && -f "setup-dvs.sh" && -f "setup-all.sh" ) {
    chdir("../api");
}

unless ( -d "data" && -f "setup-datasetfields.sh" && -f "setup-users.sh" && -f "setup-dvs.sh" && -f "setup-builtin-roles.sh" && -f "setup-all.sh" ) {
    print "\nERROR: Can't find the metadata and user/dataverse setup scripts!\n";
    print "\tAre you running the installer in the right directory?\n";
    exit 1;
}

# if there's an admin_email set from arguments, replace the value in `dv-root.json` (called by `setup-all.sh`)
if ($admin_email)
{
	print "setting contact email for root dataverse to: $admin_email\n";
	set_root_contact_email( $admin_email );
}
else
{
	print "using default contact email for root dataverse\n";
}

for my $script ( "setup-all.sh" ) {
    # (there's only 1 setup script to run now - it runs all the other required scripts)
    print "Executing post-deployment setup script " . $script . "... ";

    my $my_hostname = $CONFIG_DEFAULTS{'HOST_DNS_ADDRESS'};

    # We used to filter the supplied scripts, replacing "localhost" and the port, in 
    # case they are running Dataverse on a different port... Now we are simply requiring
    # that the port 8080 is still configured in domain.xml when they are running the 
    # installer:
    my $run_script;
    #if ( $my_hostname ne "localhost" ) {
    #    system( "sed 's/localhost:8080/$my_hostname/g' < " . $script . " > tmpscript.sh; chmod +x tmpscript.sh" );
    #    $run_script = "tmpscript.sh";
    #}
    #else {
    $run_script = $script;
    #}

    unless ( my $exit_code = system( "./" . $run_script . " > $run_script.$$.log 2>&1") == 0 ) 
    {
        print "\nERROR executing script " . $script . "!\n";
        exit 1;
    }
    print "done!\n";
}

# SOME ADDITIONAL SETTINGS THAT ARE NOT TAKEN CARE OF BY THE setup-all SCRIPT 
# NEED TO BE CONFIGURED HERE:

print "Making additional configuration changes...\n\n";


# a. Configure the Admin email in the Dataverse settings:

print "Executing " . "curl -X PUT -d " . $CONFIG_DEFAULTS{'ADMIN_EMAIL'} . " " . $API_URL . "/admin/settings/:SystemEmail" . "\n";

my $exit_code = system("curl -X PUT -d " . $CONFIG_DEFAULTS{'ADMIN_EMAIL'} . " " . $API_URL . "/admin/settings/:SystemEmail"); 
if ( $exit_code )       
{
    print "WARNING: failed to configure the admin email in the Dataverse settings!\n\n";
} 
else 
{
    print "OK.\n\n";
}
    
# b. If this installation is going to be using a remote SOLR search engine service, configure its location in the settings:

if ($CONFIG_DEFAULTS{'SOLR_LOCATION'} ne 'LOCAL')
{
    print "Executing " . "curl -X PUT -d " . $CONFIG_DEFAULTS{'SOLR_LOCATION'} . " " . $API_URL . "/admin/settings/:SolrHostColonPort" . "\n";
    my $exit_code = system("curl -X PUT -d " . $CONFIG_DEFAULTS{'SOLR_LOCATION'} . " " . $API_URL . "/admin/settings/:SolrHostColonPort"); 
    if ( $exit_code )       
    {
	print "WARNING: failed to configure the location of the remote SOLR service!\n\n";
    }
    else 
    {
	print "OK.\n\n";
    }
}



chdir($cwd);

print "\n\nYou should now have a running Dataverse instance at\n";
print "  http://" . $CONFIG_DEFAULTS{'HOST_DNS_ADDRESS'} . ":8080\n\n\n";

if ($WARFILE_LOCATION =~/([0-9]\.[0-9]\.[0-9])\.war$/) 
{
    my $version = $1;
    print "If this is a personal development installation, we recommend that you undeploy the currently-running copy \n"; 
    print "of the application, with the following asadmin command:\n\n";
    print "\t" . $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'} . '/bin/asadmin undeploy dataverse-' . $version . "\n\n";
    print "before attempting to deploy from your development environment in NetBeans.\n\n";
}
    

print "\nYour Dataverse has been configured to use DataCite, to register DOI global identifiers in the \n";
print "test name space \"10.5072\" with the \"shoulder\" \"FK2\"\n";
print "However, you have to contact DataCite (support\@datacite.org) and request a test account, before you \n";
print "can publish datasets. Once you receive the account name and password, add them to your domain.xml,\n";
print "as the following two JVM options:\n";
print "\t<jvm-options>-Ddoi.username=...</jvm-options>\n";
print "\t<jvm-options>-Ddoi.password=...</jvm-options>\n";
print "and restart glassfish\n";
print "If this is a production Dataverse and you are planning to register datasets as \n";
print "\"real\", non-test DOIs or Handles, consult the \"Persistent Identifiers and Publishing Datasets\"\n";
print "section of the Installataion guide, on how to configure your Dataverse with the proper registration\n";
print "credentials.\n\n";



# (going to skip the Rserve check; it's no longer a required, or even a recommended component)

exit 0;

# 9. FINALLY, CHECK IF RSERVE IS RUNNING:
print "\n\nFinally, checking if Rserve is running and accessible...\n";

unless ( $CONFIG_DEFAULTS{'RSERVE_PORT'} =~ /^[0-9][0-9]*$/ ) {
    print $CONFIG_DEFAULTS{'RSERVE_HOST'} . " does not look like a valid port number,\n";
    print "defaulting to 6311.\n\n";

    $CONFIG_DEFAULTS{'RSERVE_PORT'} = 6311;
}

my ( $rserve_iaddr, $rserve_paddr, $rserve_proto );

unless ( $rserve_iaddr = inet_aton( $CONFIG_DEFAULTS{'RSERVE_HOST'} ) ) {
    print STDERR "Could not look up $CONFIG_DEFAULTS{'RSERVE_HOST'},\n";
    print STDERR "the host you specified as your R server.\n";
    print STDERR "\nDVN can function without a working R server, but\n";
    print STDERR "much of the functionality concerning running statistics\n";
    print STDERR "and analysis on quantitative data will not be available.\n";
    print STDERR "Please consult the Installers guide for more info.\n";

    exit 0;
}

$rserve_paddr = sockaddr_in( $CONFIG_DEFAULTS{'RSERVE_PORT'}, $rserve_iaddr );
$rserve_proto = getprotobyname('tcp');

unless ( socket( SOCK, PF_INET, SOCK_STREAM, $rserve_proto )
    && connect( SOCK, $rserve_paddr ) )
{
    print STDERR "Could not establish connection to $CONFIG_DEFAULTS{'RSERVE_HOST'}\n";
    print STDERR "on port $CONFIG_DEFAULTS{'RSERVE_PORT'}, the address you provided\n";
    print STDERR "for your R server.\n";
    print STDERR "DVN can function without a working R server, but\n";
    print STDERR "much of the functionality concerning running statistics\n";
    print STDERR "and analysis on quantitative data will not be available.\n";
    print STDERR "Please consult the \"Installing R\" section in the Installers guide\n";
    print STDERR "for more info.\n";

    exit 0;

}

close(SOCK);
print "\nOK!\n";

# 5. CONFIGURE GLASSFISH
sub setup_glassfish {
    my $success = 1;
    my $failure = 0;

    my $glassfish_dir = $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'};

    print "\nProceeding with the Glassfish setup.\n";

# 5a. DETERMINE HOW MUCH MEMORY TO GIVE TO GLASSFISH AS HEAP:

    my $gf_heap_default = "2048m";
    my $sys_mem_total   = 0;

    if ( -e "/proc/meminfo" && open MEMINFO, "/proc/meminfo" ) {
	# Linux

	while ( my $mline = <MEMINFO> ) {
	    if ( $mline =~ /MemTotal:[ \t]*([0-9]*) kB/ ) {
		$sys_mem_total = $1;
	    }
	}
	
	close MEMINFO;

# TODO: Figure out how to determine the amount of memory when running in Docker
# because we're wondering if Dataverse can run in the free OpenShift Online
# offering that only gives you 1 GB of memory. Obviously, if this is someone's
# first impression of Dataverse, we want to to run well! What if you try to
# ingest a large file or perform other memory-intensive operations? For more
# context, see https://github.com/IQSS/dataverse/issues/4040#issuecomment-331282286
	if ( -e "/sys/fs/cgroup/memory/memory.limit_in_bytes" && open CGROUPMEM, "/sys/fs/cgroup/memory/memory.limit_in_bytes" ) {
	    print "INFO: This system has the CGROUP file /sys/fs/cgroup/memory/memory.limit_in_bytes\n";
	    while ( my $limitline = <CGROUPMEM> ) {
		### TODO: NO, WE ARE NOT NECESSARILY IN DOCKER!
		###print "We must be running in Docker! Fancy!\n";
		# The goal of this cgroup check is for
		# "Setting the heap limit for Glassfish to 750MB"
		# to change to some other value, based on memory available.
		print "INFO: /sys/fs/cgroup/memory/memory.limit_in_bytes: $limitline\n";
		my $limit_in_kb = $limitline / 1024;
		print "INFO: CGROUP limit_in_kb =  $limit_in_kb [ignoring]\n";
		# In openshift.json, notice how PostgreSQL and Solr have
		# resources.limits.memory set to "256Mi".
		# If you try to give the Dataverse/Glassfish container twice
		# as much memory (512 MB) and allow $sys_mem_total to
		# be set below, you should see the following:
		# "Setting the heap limit for Glassfish to 192MB."
		# FIXME: dataverse.war will not deploy with only 512 MB of memory.
		# Again, the goal is 1 GB total (512MB + 256MB + 256MB) for
		# Glassfish, PostgreSQL, and Solr to fit in the free OpenShift tier.
		#print "setting sys_mem_total to: $limit_in_kb\n";
		#$sys_mem_total = $limit_in_kb;
	    }
	    close CGROUPMEM;
	}
    }
    elsif ( -x "/usr/sbin/sysctl" ) 
    {
	# MacOS X, probably...

	$sys_mem_total = `/usr/sbin/sysctl -n hw.memsize`;
	chop $sys_mem_total;
	if ( $sys_mem_total > 0 ) {
	    $sys_mem_total = int( $sys_mem_total / 1024 );
	    # size in kb
	}
    }

    if ( $sys_mem_total > 0 ) {
	# setting the default heap size limit to 3/8 of the available
	# amount of memory:
	$gf_heap_default = ( int( $sys_mem_total / ( 8 / 3 * 1024 ) ) );

	print "\nSetting the heap limit for Glassfish to " . $gf_heap_default . "MB. \n";
	print "You may need to adjust this setting to better suit \n";
	print "your system.\n\n";

	#$gf_heap_default .= "m";

    }
    else 
    {
	print "\nCould not determine the amount of memory on your system.\n";
	print "Setting the heap limit for Glassfish to 2GB. You may need \n";
	print "to  adjust the value to better suit your system.\n\n";
    }

    push @CONFIG_VARIABLES, "DEF_MEM_SIZE";
    $CONFIG_DEFAULTS{"DEF_MEM_SIZE"} = $gf_heap_default;

# TODO:
# if the system has more than 4GB of memory (I believe), glassfish must
# be run with the 64 bit flag set explicitly (at least that was the case
# with the MacOS glassfish build...). Verify, and if still the case,
# add a check.

    print "\nInstalling the Glassfish PostgresQL driver... ";
#    system( "/bin/cp", "pgdriver/" . $postgres_jdbc, $glassfish_dir . "/glassfish/lib" );
    my $pgdriver_success = copy("pgdriver/" . $postgres_jdbc, $glassfish_dir . "/glassfish/lib" );

    unless ($pgdriver_success) 
    {
	print "\n*********************\n";
	print "ERROR! Failed to copy the postgres driver into " . $glassfish_dir . "/glassfish/lib - check the directory permissions!\n";
	exit 1;
    }

# more diagnostics needed?

    print "done!\n";
    
    print "\n*********************\n";
    print "PLEASE NOTE, SOME OF THE ASADMIN COMMANDS ARE GOING TO FAIL,\n";
    print "FOR EXAMPLE, IF A CONFIGURATION SETTING THAT WE ARE TRYING\n";
    print "TO CREATE ALREADY EXISTS; OR IF A JVM OPTION THAT WE ARE\n";
    print "DELETING DOESN'T. THESE \"FAILURES\" ARE NORMAL!\n";
    print "*********************\n\n";
    print "When/if asadmin asks you to \"Enter admin user name\",\n";
    print "it should be safe to hit return and accept the default\n";
    print "(which is \"admin\").\n";

    print "\nPress any key to continue...\n\n";
    
    unless ($noninteractive)
    {
	system "stty cbreak </dev/tty >/dev/tty 2>&1";
	unless ($noninteractive) {
	    my $key = getc(STDIN);
	}
	system "stty -cbreak </dev/tty >/dev/tty 2>&1";
    }
	
    print "\n";

# 5b. start domain, if not running:
    
    my $javacheck = `java -version`;
    my $exitcode  = $?;
    unless ( $exitcode == 0 ) {
	print STDERR "$javacheck\n" if $javacheck;
	print STDERR "Do you have java installed?\n";
	exit 1;
    }
    my $DOMAIN = "domain1";
    my $DOMAIN_DOWN =
	`$CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'}/bin/asadmin list-domains | grep "$DOMAIN " | grep "not running"`;
    print STDERR $DOMAIN_DOWN . "\n";
    if ($DOMAIN_DOWN) {
	print "Trying to start domain up...\n";
	if ( $current_user eq $CONFIG_DEFAULTS{'GLASSFISH_USER'} ){
		system( $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'} . "/bin/asadmin start-domain domain1" );
	}
	else
	{
		system( "sudo -u $CONFIG_DEFAULTS{'GLASSFISH_USER'} " . $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'} . "/bin/asadmin start-domain domain1" );
	}
	# TODO: (?) - retest that the domain is running now? 
    }
    else
    {
	print "domain appears to be up...\n";
    }

# 5c. create asadmin login, so that the user doesn't have to enter
# the username and password for every asadmin command, if
# access to :4848 is password-protected:

    system( $glassfish_dir. "/bin/asadmin login" );
    
# 5d. configure glassfish using ASADMIN commands:
  
    $success = &run_asadmin_script();

# CHECK EXIT STATUS, BARF IF SETUP SCRIPT FAILED:

    unless ($success) {
	print "\nERROR! Failed to configure Glassfish domain!\n";
	print "(see the error messages above - if any)\n";
	print "Aborting...\n";
	
	exit 1;
    }
    
# 5e. Additional config files:
    
    my $JHOVE_CONFIG = "jhove.conf";
    my $JHOVE_CONF_SCHEMA = "jhoveConfig.xsd";
    

    my $JHOVE_CONFIG_DIST = $JHOVE_CONFIG; 
    my $JHOVE_CONF_SCHEMA_DIST = $JHOVE_CONF_SCHEMA; 
    
# (if the installer is being run NOT as part of a distribution zipped bundle, but
# from inside the source tree - adjust the locations of the jhove config files:

    unless ( -f $JHOVE_CONFIG ) {
	$JHOVE_CONFIG_DIST = "../../conf/jhove/jhove.conf";
	$JHOVE_CONF_SCHEMA_DIST = "../../conf/jhove/jhoveConfig.xsd";
    }

# but if we can't find the files in either location, it must mean
# that they are not running the script in the correct directory - so 
# nothing else left for us to do but give up:

    unless ( -f $JHOVE_CONFIG_DIST && -f $JHOVE_CONF_SCHEMA_DIST ) {
	print "\nERROR! JHOVE configuration files not found in the config dir!\n";
	print "(are you running the installer in the right directory?\n";
	print "Aborting...\n";
	exit 1;
    }

    print "\nCopying additional configuration files... ";

    #system( "/bin/cp -f " . $JHOVE_CONF_SCHEMA_DIST . " " . $glassfish_dir . "/glassfish/domains/domain1/config" );
    my $jhove_success = copy ($JHOVE_CONF_SCHEMA_DIST, $glassfish_dir . "/glassfish/domains/domain1/config");
    unless ($jhove_success) 
    {
	print "\n*********************\n";
	print "ERROR: failed to copy jhove config file into " . $glassfish_dir . "/glassfish/domains/domain1/config - do you have write permission in that directory?";
	exit 1;
    }

# The JHOVE conf file has an absolute PATH of the JHOVE config schema file (uh, yeah...)
# - so it may need to be readjusted here: 

    if ( $glassfish_dir ne "/usr/local/glassfish4" )
    {
	system( "sed 's:/usr/local/glassfish4:$glassfish_dir:g' < " . $JHOVE_CONFIG_DIST . " > " . $glassfish_dir . "/glassfish/domains/domain1/config/" . $JHOVE_CONFIG);
    }
    else 
    {
	system( "/bin/cp -f " . $JHOVE_CONFIG_DIST . " " . $glassfish_dir . "/glassfish/domains/domain1/config" );
    }

    print "done!\n";
    
# 5f. check if glassfish is running:
# TODO.
    
# 5g. DEPLOY THE APPLICATION:

    print "\nAttempting to deploy the application.\n";
    print "Command line: " . $glassfish_dir . "/bin/asadmin deploy " . $WARFILE_LOCATION . "\n";
    unless ((
	my $exit_code =
	system( $glassfish_dir . "/bin/asadmin deploy " . $WARFILE_LOCATION )
	    ) == 0 )
    {
	print STDERR "Failed to deploy the application! WAR file: " . $WARFILE_LOCATION . ".\n";
	print STDERR "(exit code: " . $exit_code . ")\n";
	print STDERR "Aborting.\n";
	exit 1;
    }


    print "Finished configuring Glassfish and deploying the dataverse application.  \n";


    return $success;
}

sub run_asadmin_script {
    my $success = 1;
    my $failure = 0;

    # We are going to run a standalone shell script with a bunch of asadmin
    # commands to set up all the glassfish components for the application.
    # All the parameters must be passed to that script as environmental
    # variables:

    $ENV{'GLASSFISH_ROOT'}   = $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'};
    $ENV{'GLASSFISH_DOMAIN'} = "domain1";
    $ENV{'ASADMIN_OPTS'}     = "";
    $ENV{'MEM_HEAP_SIZE'}    = $CONFIG_DEFAULTS{'DEF_MEM_SIZE'};

    $ENV{'DB_PORT'} = $CONFIG_DEFAULTS{'POSTGRES_PORT'};
    $ENV{'DB_HOST'} = $CONFIG_DEFAULTS{'POSTGRES_SERVER'};
    $ENV{'DB_NAME'} = $CONFIG_DEFAULTS{'POSTGRES_DATABASE'};
    $ENV{'DB_USER'} = $CONFIG_DEFAULTS{'POSTGRES_USER'};
    $ENV{'DB_PASS'} = $CONFIG_DEFAULTS{'POSTGRES_PASSWORD'};

    $ENV{'RSERVE_HOST'} = $CONFIG_DEFAULTS{'RSERVE_HOST'};
    $ENV{'RSERVE_PORT'} = $CONFIG_DEFAULTS{'RSERVE_PORT'};
    $ENV{'RSERVE_USER'} = $CONFIG_DEFAULTS{'RSERVE_USER'};
    $ENV{'RSERVE_PASS'} = $CONFIG_DEFAULTS{'RSERVE_PASSWORD'};

    $ENV{'HOST_ADDRESS'} = $CONFIG_DEFAULTS{'HOST_DNS_ADDRESS'};

    my ($mail_server_host, $mail_server_port) = split (":", $CONFIG_DEFAULTS{'MAIL_SERVER'});

    $ENV{'SMTP_SERVER'}  = $mail_server_host;

    if ($mail_server_port) 
    {
	$ENV{'SMTP_SERVER_PORT'} = $mail_server_port; 
    }

    $ENV{'FILES_DIR'} =
      $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'} . "/glassfish/domains/" . $ENV{'GLASSFISH_DOMAIN'} . "/files";
    
    system("./glassfish-setup.sh");

    if ($?) {
        return $failure;
    }
    return $success;
}

sub create_pg_hash {
    my $pg_username = shift @_;
    my $pg_password = shift @_;

    my $encode_line = $pg_password . $pg_username;

    # for Redhat:

    ##print STDERR "executing /bin/echo -n $encode_line | md5sum\n";

    my $hash;
    if ( $WORKING_OS eq "MacOSX" ) {
        $hash = `/bin/echo -n $encode_line | md5`;
    }
    else {
        $hash = `/bin/echo -n $encode_line | md5sum`;
    }

    chop $hash;

    $hash =~ s/  \-$//;

    if ( ( length($hash) != 32 ) || ( $hash !~ /^[0-9a-f]*$/ ) ) {
        print STDERR "Failed to generate a MD5-encrypted password hash for the Postgres database.\n";
        exit 1;
    }

    return $hash;
}

sub validate_smtp_server {
    my ( $mail_server_iaddr, $mail_server__paddr, $mail_server_proto, $mail_server_status );

    $mail_server_status = 1;

    my $userentry = $CONFIG_DEFAULTS{'MAIL_SERVER'};
    my ($testserver, $testport) = split (":", $userentry);

    unless ( $mail_server_iaddr = inet_aton( $testserver ) ) {
	print STDERR "Could not look up $testserver,\n";
	print STDERR "the host you specified as your mail server\n";
	$mail_server_status = 0;
    }

    if ($mail_server_status) {
	$testport = 25 unless $testport; 
	my $mail_server_paddr = sockaddr_in( $testport, $mail_server_iaddr );
	$mail_server_proto = getprotobyname('tcp');

       unless ( socket( SOCK, PF_INET, SOCK_STREAM, $mail_server_proto )
		 && connect( SOCK, $mail_server_paddr ) )
	{
	    print STDERR "Could not establish connection to $CONFIG_DEFAULTS{'MAIL_SERVER'},\n";
	    print STDERR "the address you provided for your Mail server.\n";
	    print STDERR "Please select a valid mail server, and try again.\n\n";

	    $mail_server_status = 0;
	}

	close(SOCK);
    }

    return $mail_server_status; 
}

# support function for set_root_contact_email
sub search_replace_file
{
        my ($infile, $pattern, $replacement, $outfile) = @_;
        open (my $inp, $infile);
        local $/ = undef;
        my $txt = <$inp>;
        close $inp;
        $txt =~s/$pattern/$replacement/g;
        open (my $opf, '>:encoding(UTF-8)', $outfile);
        print $opf $txt;
        close $opf;
        return;
}
# set the email address for the default `dataverseAdmin` account
sub set_root_contact_email
{
        my ($contact_email) = @_;
        my $config_json = "data/user-admin.json";
        search_replace_file($config_json,"\"email\":\"dataverse\@mailinator.com\"","\"email\":\"$contact_email\"",$config_json);
        return;
}


sub setup_postgres {
    my $pg_local_connection = 0;
    my $pg_major_version = 0;
    my $pg_minor_version = 0;


# We'll need to do a few things as the Postgres admin user; 
# We'll assume the name of the admin user is "postgres". 
    my $POSTGRES_ADMIN_USER = "postgres";



##Handling container env

    if ($pod_name eq "start-glassfish")
    {
	# When we are in this openshift "start-glassfish" pod, we get all the 
	# Postgres configuration from the environmental variables. 
	print "Init container starting \n";
	$CONFIG_DEFAULTS{'POSTGRES_SERVER'} = $ENV{"POSTGRES_SERVER"} . "." .  $ENV{"POSTGRES_SERVICE_HOST"};
	$CONFIG_DEFAULTS{'POSTGRES_DATABASE'} = $ENV{"POSTGRES_DATABASE"};
	$CONFIG_DEFAULTS{'POSTGRES_USER'} = $ENV{"POSTGRES_USER"};
	$CONFIG_DEFAULTS{'POSTGRES_ADMIN_PASSWORD'} = $ENV{"POSTGRES_ADMIN_PASSWORD"};
	# there was a weird case of the postgres admin password option spelled differently in openshift.json 
	# - as "POSTGRESQL_ADMIN_PASSWORD"; I'm going to change it in openshift.json - but I'm leaving this
	# next line here, just in case: (L.A. -- Sept. 2018)
	$CONFIG_DEFAULTS{'POSTGRES_ADMIN_PASSWORD'} = $ENV{'POSTGRESQL_ADMIN_PASSWORD'};
	$CONFIG_DEFAULTS{'POSTGRES_PASSWORD'} = $ENV{"POSTGRES_PASSWORD"};
    }

    if ( $CONFIG_DEFAULTS{'POSTGRES_SERVER'} eq 'localhost' || $CONFIG_DEFAULTS{'POSTGRES_SERVER'} eq '127.0.0.1' ) 
    {
	$pg_local_connection = 1;
    } 
#    elsif ($postgresonly) 
#    {
#	print "In the --pg_only mode the script can only be run LOCALLY,\n";
#	print "i.e., on the server where PostgresQL is running, with the\n";
#	print "Postgres server address as localhost - \"127.0.0.1\".\n";
#	exit 1;
#    }

#If it is executing in a container, proceed easy with this all-in-one block




# 3b. LOCATE THE psql EXECUTABLE:

    if ( $pod_name eq "start-glassfish"){
        $psql_exec_path = "/usr/bin"    
    } 
    else 
    {
	my $sys_path = $ENV{'PATH'};
	my @sys_path_dirs = split( ":", $sys_path );

	for my $sys_path_dir (@sys_path_dirs) {
	    
	    if ( -x $sys_path_dir . "/psql" ) {
		$psql_exec_path = $sys_path_dir;

		last;
	    }
	}
    }

    my $psql_major_version = 0;
    my $psql_minor_version = 0;

# 3c. IF PSQL WAS FOUND IN THE PATH, CHECK ITS VERSION:

    unless ( $psql_exec_path eq "" ) {
	open( PSQLOUT, $psql_exec_path . "/psql --version|" );

	my $psql_version_line = <PSQLOUT>;
	chop $psql_version_line;
	close PSQLOUT;
    
	my ( $postgresName, $postgresNameLong, $postgresVersion ) = split( " ", $psql_version_line );

	unless ( $postgresName eq "psql" && $postgresVersion =~ /^[0-9][0-9\.]*$/ ) {
	    print STDERR "\nWARNING: Unexpected output from psql command!\n";
	}
	else 
	{
	    my (@psql_version_tokens) = split( '\.', $postgresVersion );

	    print "\n\nFound Postgres psql command, version $postgresVersion.\n\n";

	    $psql_major_version = $psql_version_tokens[0];
	    $psql_minor_version = $psql_version_tokens[1];

	    $pg_major_version = $psql_major_version;
	    $pg_minor_version = $psql_minor_version;

	}
    }

# a frequent problem with MacOSX is that the copy of psql found in the PATH
# belongs to the older version of PostgresQL supplied with the OS, which happens
# to be incompatible with the newer builds from the Postgres project; which are
# recommended to be used with Dataverse. So if this is a MacOSX box, we'll
# check what other versions of PG are available, and select the highest version
# we can find:

    if ( $WORKING_OS eq "MacOSX" ) {
	my $macos_pg_major_version = 0;
	my $macos_pg_minor_version = 0;
	
	for $macos_pg_minor_version ( "9", "8", "7", "6", "5", "4", "3", "2", "1", "0" ) {
	    if ( -x "/Library/PostgreSQL/9." . $macos_pg_minor_version . "/bin/psql" ) {
		$macos_pg_major_version = 9;
		if (   ( $macos_pg_major_version > $psql_major_version )
		       || ( $macos_pg_minor_version >= $psql_minor_version ) )
		{
		    $psql_exec_path        = "/Library/PostgreSQL/9." . $macos_pg_minor_version . "/bin";
		    $pg_major_version = $macos_pg_major_version;
		    $pg_minor_version = $macos_pg_minor_version;
		}
		last;
	    }
	}
    }

    my $psql_admin_exec = "";

    if ( $psql_exec_path eq "" ) 
    { 
	if ( $pg_local_connection || $noninteractive) 
	{
	    print STDERR "\nERROR: I haven't been able to find the psql command in your PATH!\n";
	    print STDERR "Please make sure PostgresQL is properly installed; if necessary, add\n";
	    print STDERR "the location of psql to the PATH, then try again.\n\n";
	    
	    exit 1;
	}
	else 
	{
	    print "WARNING: I haven't been able to find the psql command in your PATH!\n";
	    print "But since we are configuring a Dataverse instance to use a remote Postgres server,\n";
	    print "we can still set up the database by running a setup script on that remote server\n";
	    print "(see below for instructions).\n";
	    
	}
    } else {

	print "(Using psql version " . $pg_major_version . "." . $pg_minor_version . ": " . $psql_exec_path . "/psql)\n";


	$psql_admin_exec = "PGPASSWORD=" . $CONFIG_DEFAULTS{'POSTGRES_ADMIN_PASSWORD'} . "; export PGPASSWORD; " . $psql_exec_path; 
	$psql_exec_path = "PGPASSWORD=" . $CONFIG_DEFAULTS{'POSTGRES_PASSWORD'} . "; export PGPASSWORD; " . $psql_exec_path; 

	print "Checking if we can talk to Postgres as the admin user...\n";
    }
    
# 3d. CHECK IF WE CAN TALK TO POSTGRES AS THE ADMIN:

    if ($psql_exec_path eq "" || system( $psql_admin_exec . "/psql -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -p " . $CONFIG_DEFAULTS{'POSTGRES_PORT'} . " -U " . $POSTGRES_ADMIN_USER . " -d postgres -c 'SELECT * FROM pg_roles' > /dev/null 2>&1" ) ) 
    {
	# No, we can't. :(
	if ($pg_local_connection || $noninteractive) 
	{
	    # If Postgres is running locally, this is a fatal condition. 
	    # We'll give them some (potentially) helpful pointers and exit.

	    print "(Tried executing: " . $psql_admin_exec . "/psql -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -p " . $CONFIG_DEFAULTS{'POSTGRES_PORT'} . " -U " . $POSTGRES_ADMIN_USER . " -d postgres -c 'SELECT * FROM pg_roles' > /dev/null 2>&1) \n";
	    print "Nope, I haven't been able to connect to the local instance of PostgresQL as the admin user.\n";
	    print "\nIs postgresql running? \n";
	    print "   On a RedHat-like system, you can check the status of the daemon with\n\n";
	    print "      service postgresql start\n\n";
	    print "   On MacOSX, use Applications -> PostgresQL -> Start Server.\n";
	    print "   (or, if there's no \"Start Server\" item in your PostgresQL folder, \n";
	    print "   simply restart your MacOSX system!)\n";
	    print "\nAlso, please make sure that the daemon is listening to network connections!\n";
	    print "   - at least on the localhost interface. (See \"Installing Postgres\" section\n";
	    print "   of the installation manual).\n";
	    print "\nFinally, did you supply the correct admin password?\n";
	    print "   Don't know the admin password for your Postgres installation?\n";
	    print "   - then simply set the access level to \"trust\" temporarily (for localhost only!)\n";
	    print "   in your pg_hba.conf file. Again, please consult the \n";
	    print "   installation manual).\n";
	    exit 1;
	}
	else 
	{
	    # If we are configuring the Dataverse instance to use a Postgres server 
	    # running on a remote host, it is possible to configure the database
	    # without opening remote access for the admin user. They will simply 
	    # have to run this script in the "postgres-only" mode on that server, locally, 
	    # then resume the installation here: 
	    print "(Tried executing: " . $psql_admin_exec . "/psql -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -p " . $CONFIG_DEFAULTS{'POSTGRES_PORT'} . " -U " . $POSTGRES_ADMIN_USER . " -d postgres -c 'SELECT * FROM pg_roles' > /dev/null 2>&1)\n\n";
	    print "Haven't been able to connect to the remote Postgres server as the admin user.\n";
	    print "(Or you simply don't have psql installed on this server)\n";
	    print "It IS possible to configure a database for your Dataverse on a remote server,\n";
	    print "without having admin access to that remote Postgres installation.\n\n";
	    print "In order to do that, please copy the installer (the entire package) to the server\n";
	    print "where PostgresQL is running and run the installer with the \"--pg_only\" option:\n\n";
	    print "   ./install --pg_only\n\n";

	    print "Press any key to continue the installation process once that has been\n";
	    print "done. Or press ctrl-C to exit the installer.\n\n";
	    
	    system "stty cbreak </dev/tty >/dev/tty 2>&1";
	    my $key = getc(STDIN);
	    system "stty -cbreak </dev/tty >/dev/tty 2>&1";
	    print "\n";
	}
    }
    else 
    {
	print "Yes, we can!\n";

	# ok, we can proceed with configuring things...

	print "\nConfiguring Postgres Database:\n";

	# 4c. CHECK IF THIS DB ALREADY EXISTS:
    
	my $psql_command_dbcheck =
	    $psql_admin_exec . "/psql -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -p " . $CONFIG_DEFAULTS{'POSTGRES_PORT'} . " -U " . $POSTGRES_ADMIN_USER . " -c '' -d " . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} . ">/dev/null 2>&1";

	if ( ( my $exitcode = system($psql_command_dbcheck) ) == 0 ) 
	{    
	    if ($force) 
	    {
		print "WARNING! Database "
		    . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'}
		. " already exists but --force given... continuing.\n";
	    } 
	    else 
	    {
		print "WARNING! Database " . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} . " already exists!\n";

		if ($noninteractive)
		{
		    exit 1;
		}
		else
		{
		    print "\nPress any key to continue, or ctrl-C to exit the installer...\n\n";
        
		    system "stty cbreak </dev/tty >/dev/tty 2>&1";
		    my $key = getc(STDIN);
		    system "stty -cbreak </dev/tty >/dev/tty 2>&1";
		    print "\n";

		}
	    }
	}

	# 3e. CHECK IF THIS USER ALREADY EXISTS:
    
	my $psql_command_rolecheck =
	    $psql_exec_path . "/psql -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -c '' -d postgres " . $CONFIG_DEFAULTS{'POSTGRES_USER'} . " >/dev/null 2>&1";
	my $exitcode; 

	if ( ( $exitcode = system($psql_command_rolecheck) ) == 0 ) 
	{
	    print "User (role) " . $CONFIG_DEFAULTS{'POSTGRES_USER'} . " already exists;\n";
	    print "Proceeding.";
	}
	else 
	{
	    # 3f. CREATE DVN DB USER:
	    
	    print "\nCreating Postgres user (role) for the DVN:\n";
    
	    open TMPCMD, ">/tmp/pgcmd.$$.tmp";

	    # with md5-encrypted password:
	    my $pg_password_md5 =
		&create_pg_hash( $CONFIG_DEFAULTS{'POSTGRES_USER'}, $CONFIG_DEFAULTS{'POSTGRES_PASSWORD'} );
	    my $sql_command =
		"CREATE ROLE \""
		. $CONFIG_DEFAULTS{'POSTGRES_USER'}
	    . "\" PASSWORD 'md5"
		. $pg_password_md5
		. "' NOSUPERUSER CREATEDB CREATEROLE INHERIT LOGIN";

	    print TMPCMD $sql_command;
	    close TMPCMD;
        
	    my $psql_commandline = $psql_admin_exec . "/psql -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -p " . $CONFIG_DEFAULTS{'POSTGRES_PORT'} . " -U " . $POSTGRES_ADMIN_USER . " -d postgres -f /tmp/pgcmd.$$.tmp >/dev/null 2>&1";

	    my $out      = qx($psql_commandline 2>&1);
	    $exitcode = $?;
	    unless ( $exitcode == 0 ) 
	    {
		print STDERR "Could not create the DVN Postgres user role!\n";
		print STDERR "(SQL: " . $sql_command . ")\n";
		print STDERR "(psql exit code: " . $exitcode . ")\n";
		print STDERR "(STDERR and STDOUT was: " . $out . ")\n";
		exit 1;
	    }

	    unlink "/tmp/pgcmd.$$.tmp";
	    print "done.\n";
	}
    
	# 3g. CREATE DVN DB:
    
	print "\nCreating Postgres database:\n";
    
	my $psql_command =
	    $psql_exec_path
	    . "/createdb -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -p " . $CONFIG_DEFAULTS{'POSTGRES_PORT'} . " -U $CONFIG_DEFAULTS{'POSTGRES_USER'} "
	    . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} . " --owner="
	    . $CONFIG_DEFAULTS{'POSTGRES_USER'};

	my $out = qx($psql_command 2>&1);
        $exitcode = $?;
	unless ( $exitcode == 0 ) 
	{
	    print STDERR "Could not create Postgres database for the Dataverse app!\n";
	    print STDERR "(command: " . $psql_command . ")\n";
	    print STDERR "(psql exit code: " . $exitcode . ")\n";
	    print STDERR "(STDOUT and STDERR: " . $out . ")\n";
	    if ($force) 
	    {
		print STDERR "\ncalled with --force, continuing\n";
	    }
	    else 
	    {
		print STDERR "\naborting the installation (sorry!)\n\n";
		exit 1;
	    }
	}
    }

# Whether the user and the database were created locally or remotely, we'll now 
# verify that we can talk to that database, with the credentials of the database
# user that we want the Dataverse application to be using: 

    if ( $psql_exec_path ne "" && system( $psql_exec_path . "/psql -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . " -p " . $CONFIG_DEFAULTS{'POSTGRES_PORT'} . " -U " . $CONFIG_DEFAULTS{'POSTGRES_USER'} . " -d " . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} . " -c 'SELECT * FROM pg_roles' > /dev/null 2>&1" ) ) 
    {
	print STDERR "Oops, haven't been able to connect to the database " . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} . ",\n";
	print STDERR "running on " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'} . ", as user " . $CONFIG_DEFAULTS{'POSTGRES_USER'} . ".\n\n";
	print STDERR "Aborting the installation (sorry!)\n";
	exit 1; 
    }
}

sub import_reference_data {
    print "\npopulating the database with reference data:\n\n";

    # (we have already verified that the referenceData.sql file exists)

    my $psql_command = $psql_exec_path . "/psql -h " . $CONFIG_DEFAULTS{'POSTGRES_SERVER'}
        . " -p " . $CONFIG_DEFAULTS{'POSTGRES_PORT'}
        . " -U " . $CONFIG_DEFAULTS{'POSTGRES_USER'}
        . " -d " . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} . " -f " . $REFERENCE_DATA_SQL;

    print "EXECUTING PSQL COMMAND: $psql_command\n";
    unless ( ( my $exitcode = system("$psql_command") ) == 0 )
    {
        print "WARNING: Could not pre-populate Postgres database for the Dataverse application!\n";
        print "(command: " . $psql_command . ")\n";
        print "(psql exit code: " . $exitcode . ")\n";
        print "\nYou must populate the database in order for all the features of your \n";
        print "new Dataverse to be available. \n";
        print "\n";
        print "You can try this again, by executing the following on the command line:\n";
        print "   psql -U $CONFIG_DEFAULTS{'POSTGRES_USER'} -d $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} -f $REFERENCE_DATA_SQL\n";
        print "then re-start glassfish  \n\n";
        print "\n";
        print "If it's still failing, please consult the installation manual and/or\n";
        print "seek support from the Dataverse team.\n\n";
        
        print "Press any key to continue... ";
        
	unless ($noninteractive) 
	{
	    system "stty cbreak </dev/tty >/dev/tty 2>&1";
	    my $key = getc(STDIN);
	    system "stty -cbreak </dev/tty >/dev/tty 2>&1";
	    print "\n";
	}
    }
    else
    {
        print "\nOK, done!\n";
    }
}

